from django.contrib.auth.hashers import make_password, check_password
from django.shortcuts import redirect
# 导包
from django.http import HttpResponse, HttpResponseRedirect, JsonResponse
# 导入类视图
from django.views import View

# import json
# from django.core.serializers import serialize
from rest_framework.response import Response
from rest_framework.views import APIView
# 导入加密库
# import hashlib

# 导入图片库
# 绘画库
from PIL import ImageDraw
# 字体库
from PIL import ImageFont
# 图片库
from PIL import Image

# 随机库
import random
# 文件流
import io

import requests

# 导入上传文件夹配置
from mydjango.settings import UPLOAD_ROOT
import os

# 导入原生sql模块
from django.db import connection

# import jwt

# 导入redis数据库
# import redis

# 导入时间模块
# import time

# 导入公共目录变量
# from mydjango.settings import BASE_DIR

# 导包
from django.db.models import Q, F

# 导入dwebsocket的库
# from dwebsocket.decorators import accept_websocket
# import uuid
#
# from myapp.models import User
#
# from django.utils.deprecation import MiddlewareMixin
#
# from django.http import QueryDict

# 类视图调用
# from django.utils.decorators import method_decorator

# 事务操作
# from django.db import transaction

import jwt
import datetime
from myapp.serializers import *

# def make_password(my_password, salt):
#     # 生成对象
#     md5 = hashlib.md5()
#     # 定义加密对象
#     sign_str = my_password + salt
#     # 转码
#     sign_utf8 = str(sign_str).encode(encoding="utf-8")
#     # 加密
#     md5.update(sign_utf8)
#     # 生成密文
#     md5_server = md5.hexdigest()
#     return md5_server


from redis import Redis


# 文件上传
class Uploader(View):
    def post(self, request):
        # 接受参数
        file = request.FILES.get("file")
        # 写文件
        with open(os.path.join(UPLOAD_ROOT, "", file.name), "wb") as f:
            for chunk in file.chunks():
                f.write(chunk)
        return HttpResponse(
            json.dumps({"filename": file.name}, ensure_ascii=False), content_type="application/json"
        )


# 用户接口
class UserView(APIView):
    def get(self, request):
        token = request.GET.get("token")
        decode_token = jwt.decode(token, key="123", algorithms="HS256")
        uid = decode_token["data"]["uid"]
        u_list = User.objects.filter(id=uid)
        u_ser = UserSer(u_list, many=True)
        return Response({"msg": "当前用户信息已获取", "code": 200, "data": u_ser.data})


# 头像接口
class PictureView(APIView):
    def put(self, request):
        token = request.data.get("token")
        pic_file = request.data.get("file")

        # 前端选择的头像文件写入到UPLOAD_ROOT中路径目标的文件夹中
        with open(os.path.join(UPLOAD_ROOT, "", pic_file.name), "wb") as f:
            for chunk in pic_file.chunks():
                f.write(chunk)

        decode_token = jwt.decode(token, key="123", algorithms="HS256")
        uid = decode_token["data"]["uid"]

        user = User.objects.get(id=uid)
        User.objects.filter(id=uid).update(picture=pic_file)
        return Response({"msg": "头像设置成功", "code": 200, "pic": user.picture})


# 头像清空接口
class DelPicView(APIView):
    def put(self, request):
        token = request.data.get("token")
        decode_token = jwt.decode(token, key="123", algorithms="HS256")
        uid = decode_token["data"]["uid"]
        user = User.objects.get(id=uid)
        if user.picture != None:
            User.objects.filter(id=uid).update(picture=None)
            return Response({"msg": "已重置头像", "code": 200})
        else:
            return Response({"msg": "当前暂无头像", "code": 404})


# 定义验证码类
class MyImgCode(View):
    # 内置类方法
    def get_random_color(self):
        R = random.randrange(255)
        G = random.randrange(255)
        B = random.randrange(255)
        return (R, G, B)

    def get(self, request):
        # 定义画布,赋值宽，高
        img_size = (120, 50)
        # 定义图像对象
        image = Image.new("RGB", img_size, "white")
        # 定义画笔
        draw = ImageDraw.Draw(image, "RGB")
        # 定义字符串
        source = "0123456789abcdefghijklmnobqrstuvwxyz"
        # 定义容器
        code_str = ""
        for i in range(4):
            # 获取字符颜色
            text_color = self.get_random_color()
            # 获取随机字符
            tmp_num = random.randrange(len(source))
            random_str = source[tmp_num]
            code_str += random_str
            draw.text((10 + 30 * i, 20), random_str, text_color)
        buf = io.BytesIO()
        image.save(buf, "png")

        # 保存验证码
        # request.session["code"] = code_str

        re = Redis()
        re.set("code", code_str)
        # 返回响应
        return HttpResponse(buf.getvalue(), "image/png")


# 用户注册
class Register(APIView):
    def post(self, request):
        # 接受参数
        username = request.data.get("username")
        password = make_password(request.data.get("password"))
        phone = request.data.get("phone")
        email = request.data.get("email")
        gender = request.data.get("gender")
        try:
            user = User(username=username, password=password, phone=phone, email=email, gender=gender)
            user.save()
            return Response({"msg": "注册成功", "code": 200})
        except Exception as e:
            print(e)
            return Response({"msg": "用户已存在", "code": 405})


# 用户登录
class Login(APIView):
    def post(self, request):
        username = request.data.get("username", None)
        phone = request.data.get("phone", None)
        email = request.data.get("email", None)
        password = request.data.get("password", None)
        img_code = request.data.get("img_code")
        active = request.data.get("active", None)

        # print(username, phone, email, password, code, active, '-------------')
        re = Redis()
        code = re.get("code").decode()
        print(img_code, code, '-------------')
        if img_code != code:
            return Response({"msg": "验证码错误", "code": 400})

        # 判断用户选择的登录方式（注意从0开始，0为默认的方式）
        if active == 1:
            user = User.objects.filter(phone=phone).first()
        elif active == 2:
            user = User.objects.filter(email=email).first()
        else:
            user = User.objects.filter(username=username).first()
        if user and check_password(password, user.password):
            # 生成JWT
            encode_jwt = jwt.encode(payload={
                "exp": int((datetime.datetime.now() + datetime.timedelta(hours=5)).timestamp()),
                "data": {"uid": user.id, "username": user.username}
            }, key="123", algorithm="HS256")
            # 将字节解码成字符串
            encode_str_jwt = encode_jwt.decode()
            # 解密
            decode_jwt = jwt.decode(
                encode_str_jwt,
                key="123", algorithms="HS256")

            return Response(
                {"msg": "登录成功", "code": 200, "token": encode_str_jwt, "uid": decode_jwt["data"]["uid"], "u_name": decode_jwt["data"]["username"]}
            )
        elif not User.objects.filter(Q(username=username) | Q(phone=phone) | Q(email=email)).first():
            return Response({"msg": "用户不存在 请先注册", "code": 404})
        else:
            return Response({"msg": "用户名或密码错误", "code": 400})


# 个人中心修改密码
class CenterView(APIView):
    def put(self, request):
        token = request.data.get("token")
        username = request.data.get("username")
        password = request.data.get("password")
        new_password = request.data.get("new_password")

        decode_token = jwt.decode(token, key="123", algorithms="HS256")
        print(decode_token)

        uid = decode_token["data"]["uid"]
        user = User.objects.get(id=uid)
        if username != decode_token["data"]["username"]:
            return Response({"msg": "用户验证错误", "code": 405})
        if check_password(password, user.password):
            User.objects.filter(id=uid).update(password=make_password(new_password))
            return Response({"msg": "密码修改成功,请重新登录", "code": 200})
        else:
            return Response({"msg": "原密码错误", "code": 400})


# 钉钉三方登录
import time
import hmac
import base64
from hashlib import sha256
import urllib
import json


# 构造钉钉登录url
def ding_url(request):
    appid = 'dingoaukgkwqknzjvamdqh'
    redirect_uri = 'http://localhost:8000/dingding_back/'

    return redirect(
        'https://oapi.dingtalk.com/connect/qrconnect?appid='
        +
        appid
        +
        '&response_type=code&scope=snsapi_login&state=STATE&redirect_uri=' + redirect_uri)


# 构造钉钉回调方法
def ding_back(request):
    # 获取code
    code = request.GET.get("code")

    t = time.time()
    # 时间戳
    timestamp = str((int(round(t * 1000))))

    appSecret = 'ly-AzMKMmCKQP3geaILT_An32kEfKO3HeOtApy5CgKwjytevVZC0WYsT2gxMB160'
    # 构造签名
    signature = base64.b64encode(
        hmac.new(appSecret.encode('utf-8'), timestamp.encode('utf-8'), digestmod=sha256).digest())

    # 请求接口，换取钉钉用户名
    payload = {'tmp_auth_code': code}
    headers = {'Content-Type': 'application/json'}
    res = requests.post('https://oapi.dingtalk.com/sns/getuserinfo_bycode?signature=' + urllib.parse.quote(
        signature.decode("utf-8")) + "&timestamp=" + timestamp + "&accessKey=dingoaukgkwqknzjvamdqh",
                        data=json.dumps(payload), headers=headers)

    res_dict = json.loads(res.text)
    print(res_dict)
    return HttpResponse(res.text)


# 权限接口
class NodeView(APIView):
    def get(self, request):
        node_list = Node.objects.all()
        node_ser = NodeSer(node_list, many=True)
        return Response({"msg": "获取权限成功", "code": 200, "data": node_ser.data})


# 用户授权(the user authorization)
class Authorization(APIView):
    def post(self, request):
        uid = request.data.get("uid")  # 用户id
        node_id = request.data.get("nodeid")  # 权限id
        print(uid, node_id)
        Access.objects.create(uid=uid, nodeid=node_id)
        return Response({"msg": "授权成功", "code": 200})

        # node_ser = AccessSer(data=request.data)
        # print(request.data)
        # if node_ser.is_valid():
        #     node_ser.save()
        #     return Response({"msg": "授权成功", "code": 200})
        # else:
        #     print(node_ser.errors)
        #     return Response({"msg": "授权失败", "code": 400})


def dictfetchall(cursor):
    desc = cursor.description
    return [
        dict(zip([col[0] for col in desc], row))
        for row in cursor.fetchall()
    ]


# 获取某个用户的权限
class GetUserAccess(View):
    def get(self, request):
        uid = request.GET.get("uid")
        # 建立查询游标
        cursor = connection.cursor()
        # 执行sql
        cursor.execute(
            "SELECT a.username, c.node_name,c.id from user a left join access b on a.id =  b.uid left join node c on b.node_id = c.id where a.id = %s"
            % uid
        )
        # 获取结果查询集
        # res = cursor.fetchall()
        res = dictfetchall(cursor)
        # 返回，ensure_ascii=False/防止节点中有中文，如果有，会将中文加密从乱码
        return HttpResponse(json.dumps(res, indent=4, ensure_ascii=False), content_type="application/json")


user = 0b111
permission = 0b001


# 装饰器
def my_decorator(func):
    def wrapper(request, *args, **kwargs):
        print("装饰器被调用")
        if user & permission:
            return func(request, *args, **kwargs)
        else:
            return HttpResponse("无权限")
    return wrapper


# 上传头像
@my_decorator
def upload_img(request):
    return HttpResponse("已上传")


# 构造课程分类层级关系（树）
def get_tree(data):
    lists = []
    tree = {}
    for item in data:
        tree[item["id"]] = item
    for i in data:
        if not i["pid"]:
            lists.append(tree[i["id"]])
        else:
            parent_id = i["pid"]
            if "children" not in tree[parent_id]:
                tree[parent_id]["children"] = []
            tree[parent_id]["children"].append(tree[i["id"]])
    return lists


# 获取课程分类
def get_cate(request):
    # 建立查询游标
    cursor = connection.cursor()
    # 执行sql
    cursor.execute(
        "SELECT * from cate"
    )
    # 获取结果查询集
    # res = cursor.fetchall()
    res = dictfetchall(cursor)
    res = get_tree(res)
    return HttpResponse(
        json.dumps(res, indent=4, ensure_ascii=False), content_type="application/json"
    )


# 课程接口
class CateView(APIView):
    def get(self, request):
        c_list = Cate.objects.all()
        c_ser = CateSer(c_list, many=True)
        return Response({"msg": "课程已获取", "data": c_ser.data})

    def post(self, request):
        cate_ser = CateSer(data=request.data)
        if cate_ser.is_valid():
            cate_ser.save()
            return Response({"msg": "课程添加成功", "code": 200})
        else:
            print(cate_ser.errors)
            return Response({"msg": "课程添加失败", "code": 400})
